<?php

/*

Copyright (C) 2012 Jim Xochellis
(homepage: https://sites.google.com/site/xochellis/)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

function ShowImplementationCode($order_is_ascending, $functor_name, $struct_type, 
	$use_const_reference, $field_desc, $update_creation_counter = false)
{
	$delim = " \n\t,;";
	
	$functor_name = strtok($functor_name, $delim);
	
	// Handle and fix struct type
	$struct_type_first_token = strtok($struct_type, $delim);
	
	while ($struct_type_first_token == "const")
		$struct_type_first_token = strtok($delim);
	
	$struct_type = $struct_type_first_token;
		
	// Handle and fix field names
	
	$field_names = array();
	$field_desc_token = strtok($field_desc, $delim);
	
	while ( ! empty($field_desc_token) )
	{
		array_push($field_names, $field_desc_token);
		$field_desc_token = strtok($delim);
	}
	
	$field_names_count = count($field_names);
	
	// Validate user input
	
	if ( empty($functor_name) )
	{
		error_msg("Cannot create functor: No valid functor name found!");
		return FALSE;
	}

	if ( empty($struct_type) )
	{
		error_msg("Cannot create functor: No valid struct/class type found!");
		return FALSE;
	}
		
	if ( $field_names_count == 0 )
	{
		error_msg("Cannot create functor: No valid field/method names found!");
		return FALSE;
	}
	elseif ( $field_names_count > 4)
	{
		error_msg("Cannot create functor: More than four field/method names found!");
		return FALSE;	
	}
	
	//--------------------------------------------------------
	// Main functor creation code
	
	if ( $use_const_reference )
		$param_type = cpp_keyword("const"). " " . user_var($struct_type) . " " . cpp_operator("&amp;");
	else
		$param_type = "" . user_var($struct_type) . " " . cpp_operator("&amp;");
		
	DoProduceFunctorCode($functor_name, $struct_type, $param_type, $field_names, $order_is_ascending);
	DoProduceLambdaCode($param_type, $field_names, $order_is_ascending);
	DoProduceOperatorCode($param_type, $field_names, $order_is_ascending);
	
	if ( $update_creation_counter )
	{
		$db_host_name		= "";
		$db_user_name		= "";
		$db_user_password	= "";
		
		//mysql_cfg.php overrides the database connection settings
		include "config/mysql_cfg.php";

		$db_connection = mysql_connect($db_host_name, $db_user_name, $db_user_password);
		
		if ( $db_connection )
		{
			$db_list = mysql_list_dbs($db_connection);
			
			if ( mysql_select_db("strict_weak_ordering_wizard", $db_connection) )
				$result = mysql_query("UPDATE counters SET value=value+1 WHERE name='creation' AND enable=1", $db_connection);

			mysql_close($db_connection);
		}
	}
	
	return TRUE;
}

function DoProduceFunctorCode($functor_name, $struct_type, $param_type, $field_names, $order_is_ascending)
{
	$field_names_count = count($field_names);
	
	echo "<br/>";
	echo "<h3>Strict-Weak-Ordering Functor Implementation (recommended)</h3>\n\n";
	echo "<pre class=\"sub-box\">\n\n";
	echo cpp_include_header("functional"), " ", cpp_comment("//Header file requirement"), "\n\n";
	echo cpp_keyword("struct"), " ", user_var($functor_name), "\n";
	echo "\t: ", cpp_keyword("public"), " std::binary_function&lt;",
			user_var($struct_type), ", ", user_var($struct_type), ", ", cpp_keyword("bool"), "&gt;\n";
	echo "{\n";
	echo "\t", cpp_keyword("bool operator"), "() (", $param_type, "left, ", $param_type, "right) ", cpp_keyword("const"), "\n";
	
	DoProduceInternalCode($field_names, $order_is_ascending, "\t");
	
	echo "};\n\n";
	
	echo "<code class=\"comment\">\n";
	echo "// Indicative usage with std::sort\n";
	echo "// -------------------------------\n";
	echo "// std::vector&lt;", user_var($struct_type), "&gt; v;\n";
	echo "// std::sort(v.begin(), v.end(), ", user_var($functor_name), "());\n\n\n";
	
	echo "// Indicative usage with std::set\n";
	echo "// ------------------------------\n";
	echo "// std::set&lt;", user_var($struct_type), ", ", user_var($functor_name), "&gt; s;\n";
	echo "</code>\n";
	
	echo "</pre>\n\n";
}

function DoProduceOperatorCode($param_type, $field_names, $order_is_ascending)
{	
	echo "<br/>";
	echo "<h3>Less-Than Operator Implementation (not recommended)</h3>\n\n";
	echo "<pre class=\"sub-box\">\n\n";
	
	echo cpp_keyword("inline bool operator"), "&lt; (", $param_type, "left, ", $param_type, "right)\n";
	
	DoProduceInternalCode($field_names, $order_is_ascending, "");
	
	echo "\n</pre>\n\n";
}

function DoProduceLambdaCode($param_type, $field_names, $order_is_ascending)
{	
	echo "<br/>";
	echo "<h3>Strict-Weak-Ordering Lambda Implementation (C++11 only)</h3>\n\n";
	echo "<pre class=\"sub-box\">\n\n";
	
	echo "[] (", $param_type, "left, ", $param_type, "right) -> ", cpp_keyword("bool"), "\n";
	
	echo "{\n";
	
	$field_names_count = count($field_names);

	if ( $order_is_ascending )
	{
		$lhs = "left.";
		$rhs = "right.";
	}
	else
	{
		$lhs = "right.";
		$rhs = "left.";		
	}
	
	if ($field_names_count == 1)
	{
		echo "\t", cpp_keyword("return"), " (", $lhs, user_var($field_names[0]), 
			" ", cpp_operator("&lt;"), " ", $rhs, user_var($field_names[0]), ");\n";
	}
	else
	{	
		echo "\t", cpp_keyword("return"), " std::tie(";
		
		for ( $n = 0; $n < $field_names_count-1; ++$n)
		{
			echo $lhs, user_var($field_names[$n]), ", ";
		}
		
		echo $lhs, user_var($field_names[$field_names_count-1]), ") ";
		echo cpp_operator("&lt;"), " std::tie(";
		
		for ( $n = 0; $n < $field_names_count-1; ++$n)
		{
			echo $rhs, user_var($field_names[$n]), ", ";
		}
		
		echo $rhs, user_var($field_names[$field_names_count-1]), ");\n";
	}
		
	echo "}\n";
	
	echo "\n</pre>\n\n";
}

function DoProduceInternalCode($field_names, $order_is_ascending, $indent)
{
	$field_names_count = count($field_names);

	echo $indent, "{\n";
	$indent .= "\t";
	
	if ( $order_is_ascending )
	{
		$lhs = "left.";
		$rhs = "right.";
	}
	else
	{
		$lhs = "right.";
		$rhs = "left.";		
	}
	
	for ( $n = 0; $n < $field_names_count-1; ++$n)
	{
		echo $indent, cpp_keyword("if"), " (left.", user_var($field_names[$n]), " ",
				cpp_operator("=="), " right.", user_var($field_names[$n]), ")\n";
		$indent .= "\t";		
	}
	
	echo $indent, cpp_keyword("return"), " (", $lhs, user_var($field_names[$field_names_count-1]), " ",
			cpp_operator("&lt;"), " ", $rhs, user_var($field_names[$field_names_count-1]), ");\n";

	for ( $n = $field_names_count-1; $n > 0; --$n)
	{
		$indent = substr($indent, 0, strlen($indent)-1);
		echo $indent, cpp_keyword("else"), "\n";
		echo $indent, "\t", cpp_keyword("return"), " (", $lhs, user_var($field_names[$n-1]), " ",
				cpp_operator("&lt;"), " ", $rhs, user_var($field_names[$n-1]), ");\n";
	}

	$indent = substr($indent, 0, strlen($indent)-1);
	echo $indent, "}\n";
}

// -------------------------------------------------------------
// Helper functions

function error_msg($msg)
{
	echo "<h3 style=\"color: red; text-align: center;\"><i>\n";
	echo $msg;
	echo "</i></h3>\n\n";	
}

function user_var($var)
{
	return "<strong>" . $var . "</strong>";
}

function cpp_include_header($heade_file)
{
	return "<code class=\"keyword\">#include</code> <code class=\"header\">&lt;" . $heade_file . "&gt;</code>";
}

function cpp_comment($comment)
{
	return "<code class=\"comment\">" . $comment . "</code>";
}

function cpp_keyword($keyword)
{
	return "<code class=\"keyword\">" . $keyword . "</code>";
}

function cpp_operator($operator)
{
	return "<code class=\"operator\">" . $operator . "</code>";
}

?>

